home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / src / balloon.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-02-14  |  11.9 KB  |  490 lines

  1. /* 
  2.  *  Window Maker window manager
  3.  * 
  4.  *  Copyright (c) 1998 Alfredo K. Kojima
  5.  * 
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 
  19.  *  USA.
  20.  */
  21.  
  22. #include "wconfig.h"
  23.  
  24. #ifdef BALLOON_TEXT
  25.  
  26. #include <X11/Xlib.h>
  27. #include <X11/Xutil.h>
  28. #ifdef SHAPED_BALLOON
  29. #include <X11/extensions/shape.h>
  30. #endif
  31.  
  32. #include <stdlib.h>
  33. #include <string.h>
  34.  
  35. #include <wraster.h>
  36.  
  37. #include "WindowMaker.h"
  38. #include "screen.h"
  39. #include "texture.h"
  40. #include "wcore.h"
  41. #include "framewin.h"
  42. #include "icon.h"
  43. #include "appicon.h"
  44. #include "funcs.h"
  45. #include "workspace.h"
  46. #include "balloon.h"
  47.  
  48.  
  49.  
  50. extern WPreferences wPreferences;
  51.  
  52. typedef struct _WBalloon {
  53.     Window window;
  54.  
  55. #ifdef SHAPED_BALLOON
  56.     GC monoGC;
  57. #endif
  58.     int prevType;
  59.  
  60.     Window objectWindow;
  61.     char *text;
  62.     int h;
  63.     
  64.     WMHandlerID timer;
  65.     
  66.     Pixmap contents;
  67.     
  68.     char mapped;
  69.     char ignoreTimer;
  70. } WBalloon;
  71.  
  72.  
  73. #define TOP    0
  74. #define BOTTOM    1
  75. #define LEFT    0
  76. #define RIGHT    2
  77.  
  78. #define TLEFT    (TOP|LEFT)
  79. #define TRIGHT     (TOP|RIGHT)
  80. #define BLEFT    (BOTTOM|LEFT)
  81. #define BRIGHT    (BOTTOM|RIGHT)
  82.  
  83.  
  84. #ifdef SHAPED_BALLOON
  85.  
  86. #define     SPACE    12
  87. #define MIN(a,b)    ((a)<(b)?(a):(b))
  88. #define MAX(a,b)    ((a)>(b)?(a):(b))
  89.  
  90. static void
  91. drawBalloon(Pixmap pix, GC gc, int x, int y, int w, int h, int side)
  92. {
  93.     int rad = h*3/10;
  94.     XPoint pt[3];
  95.     
  96.     XFillArc(dpy, pix, gc, x, y, rad, rad, 90*64, 90*64);
  97.     XFillArc(dpy, pix, gc, x, y+h-1-rad, rad, rad, 180*64, 90*64);
  98.     
  99.     XFillArc(dpy, pix, gc, x+w-1-rad, y, rad, rad, 0*64, 90*64);
  100.     XFillArc(dpy, pix, gc, x+w-1-rad, y+h-1-rad, rad, rad, 270*64, 90*64);
  101.     
  102.     XFillRectangle(dpy, pix, gc, x, y+rad/2, w, h-rad);
  103.     XFillRectangle(dpy, pix, gc, x+rad/2, y, w-rad, h);
  104.  
  105.     if (side & BOTTOM) {
  106.     pt[0].y = y+h-1;
  107.     pt[1].y = y+h-1+SPACE;
  108.     pt[2].y = y+h-1;
  109.     } else {
  110.     pt[0].y = y;
  111.     pt[1].y = y-SPACE;
  112.     pt[2].y = y;
  113.     }
  114.     if (side & RIGHT) {
  115.     pt[0].x = x+w-h+2*h/16;
  116.     pt[1].x = x+w-h+11*h/16;
  117.     pt[2].x = x+w-h+7*h/16;
  118.     } else {
  119.     pt[0].x = x+h-2*h/16;
  120.     pt[1].x = x+h-11*h/16;
  121.     pt[2].x = x+h-7*h/16;
  122.     }
  123.     XFillPolygon(dpy, pix, gc, pt, 3, Convex, CoordModeOrigin);
  124. }
  125.  
  126.  
  127. static Pixmap
  128. makePixmap(WScreen *scr, int width, int height, int side, Pixmap *mask)
  129. {
  130.     WBalloon *bal = scr->balloon;
  131.     Pixmap bitmap;
  132.     Pixmap pixmap;
  133.     int x, y;
  134.  
  135.     bitmap = XCreatePixmap(dpy, scr->root_win, width+SPACE, height+SPACE, 1);
  136.  
  137.     if (!bal->monoGC) {
  138.     bal->monoGC = XCreateGC(dpy, bitmap, 0, NULL);
  139.     }
  140.     XSetForeground(dpy, bal->monoGC, 0); 
  141.     XFillRectangle(dpy, bitmap, bal->monoGC, 0, 0, width+SPACE, height+SPACE);
  142.     
  143.     pixmap = XCreatePixmap(dpy, scr->root_win, width+SPACE, height+SPACE,
  144.                scr->w_depth);
  145.     XSetForeground(dpy, scr->draw_gc, scr->black_pixel);
  146.     XFillRectangle(dpy, pixmap, scr->draw_gc, 0, 0, width+SPACE, height+SPACE);
  147.  
  148.     if (side & BOTTOM) {
  149.     y = 0;
  150.     } else {
  151.     y = SPACE;
  152.     }
  153.     x = 0;
  154.  
  155.     XSetForeground(dpy, bal->monoGC, 1);
  156.     drawBalloon(bitmap, bal->monoGC, x, y, width, height, side);
  157.     XSetForeground(dpy, scr->draw_gc, scr->white_pixel);
  158.     drawBalloon(pixmap, scr->draw_gc, x+1, y+1, width-2, height-2, side);
  159.  
  160.     *mask = bitmap;
  161.  
  162.     return pixmap;
  163. }
  164.  
  165.  
  166. static void
  167. showText(WScreen *scr, int x, int y, int h, int w, char *text)
  168. {
  169.     int width;
  170.     int height;
  171.     Pixmap pixmap;
  172.     Pixmap mask;
  173.     WMFont *font = scr->info_text_font;
  174.     int side = 0;
  175.     int ty;
  176.     int bx, by;
  177.  
  178.     if (scr->balloon->contents)
  179.     XFreePixmap(dpy, scr->balloon->contents);
  180.  
  181.     width = WMWidthOfString(font, text, strlen(text))+16;
  182.     height = WMFontHeight(font) + 4;
  183.     
  184.     if (height < 16)
  185.     height = 16;
  186.     if (width < height)
  187.     width = height;
  188.  
  189.  
  190.     if (x + width > scr->scr_width) {
  191.     side = RIGHT;
  192.     bx = x - width + w/2;
  193.     if (bx < 0)
  194.         bx = 0;
  195.     } else {
  196.     side = LEFT;
  197.     bx = x + w/2;
  198.     }
  199.     if (bx + width > scr->scr_width)
  200.     bx = scr->scr_width - width;
  201.  
  202.     if (y - (height + SPACE) < 0) {
  203.     side |= TOP;
  204.     by = y+h-1;
  205.     ty = SPACE;
  206.     } else {
  207.     side |= BOTTOM;
  208.     by = y - (height + SPACE);
  209.     ty = 0;
  210.     }
  211.     pixmap = makePixmap(scr, width, height, side, &mask);
  212.  
  213.     XSetForeground(dpy, scr->info_text_gc, scr->black_pixel);
  214.  
  215.     WMDrawString(scr->wmscreen, pixmap, scr->info_text_gc, font, 8,
  216.          ty + (height - WMFontHeight(font))/2,
  217.          text, strlen(text));
  218.  
  219.     XSetWindowBackgroundPixmap(dpy, scr->balloon->window, pixmap);
  220.     scr->balloon->contents = pixmap;
  221.  
  222.     XResizeWindow(dpy, scr->balloon->window, width, height+SPACE);
  223.     XShapeCombineMask(dpy, scr->balloon->window, ShapeBounding, 0, 0, mask,
  224.               ShapeSet);
  225.     XFreePixmap(dpy, mask);
  226.     XMoveWindow(dpy, scr->balloon->window, bx, by);
  227.     XMapRaised(dpy, scr->balloon->window);
  228.     
  229.     scr->balloon->mapped = 1;
  230. }
  231. #else /* !SHAPED_BALLOON */
  232. static void
  233. showText(WScreen *scr, int x, int y, int h, int w, char *text)
  234. {
  235.     int width;
  236.     int height;
  237.     Pixmap pixmap;
  238.     WMFont *font = scr->info_text_font;
  239.  
  240.     if (scr->balloon->contents)
  241.     XFreePixmap(dpy, scr->balloon->contents);
  242.  
  243.     width = WMWidthOfString(font, text, strlen(text))+8;
  244.     height = WMFontHeight(font) + 4;
  245.  
  246.     if (x < 0)
  247.     x = 0;
  248.     else if (x + width > scr->scr_width-1)
  249.     x = scr->scr_width - width;
  250.     
  251.     if (y - height - 2 < 0) {
  252.     y += h;
  253.     if (y < 0)
  254.         y = 0;
  255.     } else {
  256.     y -= height + 2;
  257.     }
  258.     
  259.     if (scr->window_title_texture[0])
  260.     XSetForeground(dpy, scr->draw_gc,
  261.                scr->window_title_texture[0]->any.color.pixel);
  262.     else
  263.     XSetForeground(dpy, scr->draw_gc, scr->light_pixel);
  264.  
  265.     pixmap = XCreatePixmap(dpy, scr->root_win, width, height, scr->w_depth);
  266.     XFillRectangle(dpy, pixmap, scr->draw_gc, 0, 0, width, height);
  267.  
  268.     XSetForeground(dpy, scr->info_text_gc, scr->window_title_pixel[0]);
  269.  
  270.     WMDrawString(scr->wmscreen, pixmap, scr->info_text_gc, font, 
  271.          4, 2, text, strlen(text));
  272.  
  273.     XResizeWindow(dpy, scr->balloon->window, width, height);
  274.     XMoveWindow(dpy, scr->balloon->window, x, y);
  275.  
  276.     XSetWindowBackgroundPixmap(dpy, scr->balloon->window, pixmap);
  277.     XClearWindow(dpy, scr->balloon->window);
  278.     XMapRaised(dpy, scr->balloon->window);
  279.  
  280.     scr->balloon->contents = pixmap;
  281.     
  282.     scr->balloon->mapped = 1;
  283. }
  284. #endif /* !SHAPED_BALLOON */
  285.  
  286.  
  287. static void
  288. showBalloon(WScreen *scr)
  289. {
  290.     int x, y;
  291.     Window foow;
  292.     unsigned foo, w;
  293.  
  294.     if (scr->balloon) {
  295.     scr->balloon->timer = NULL;
  296.     scr->balloon->ignoreTimer = 1;
  297.     }
  298.  
  299.     if (!XGetGeometry(dpy, scr->balloon->objectWindow, &foow, &x, &y,
  300.               &w, &foo, &foo, &foo)) {
  301.     scr->balloon->prevType = 0;
  302.     return;
  303.     }
  304.     showText(scr, x, y, scr->balloon->h, w, scr->balloon->text);
  305. }
  306.  
  307.  
  308.  
  309. static void
  310. frameBalloon(WObjDescriptor *object)
  311. {
  312.     WFrameWindow *fwin = (WFrameWindow*)object->parent;
  313.     WScreen *scr = fwin->core->screen_ptr;
  314.  
  315.     if (fwin->titlebar != object->self
  316.     || !fwin->flags.is_client_window_frame) {
  317.     wBalloonHide(scr);
  318.     return;
  319.     }
  320.     if (fwin->title && fwin->flags.incomplete_title) {
  321.     scr->balloon->h = (fwin->titlebar ? fwin->titlebar->height : 0);
  322.     scr->balloon->text = wstrdup(fwin->title);
  323.     scr->balloon->objectWindow = fwin->core->window;
  324.     scr->balloon->timer = WMAddTimerHandler(BALLOON_DELAY,
  325.                         (WMCallback*)showBalloon, scr);
  326.     }
  327. }
  328.  
  329.  
  330. static void
  331. miniwindowBalloon(WObjDescriptor *object)
  332. {
  333.     WIcon *icon = (WIcon*)object->parent;
  334.     WScreen *scr = icon->core->screen_ptr;
  335.  
  336.     if (!icon->icon_name) {
  337.     wBalloonHide(scr);
  338.     return;
  339.     }
  340.     scr->balloon->h = icon->core->height;
  341.     scr->balloon->text = wstrdup(icon->icon_name);
  342.     scr->balloon->objectWindow = icon->core->window;
  343.     if ((scr->balloon->prevType == object->parent_type
  344.     || scr->balloon->prevType == WCLASS_APPICON)
  345.     && scr->balloon->ignoreTimer) {
  346.     XUnmapWindow(dpy, scr->balloon->window);
  347.     showBalloon(scr);
  348.     } else {
  349.     scr->balloon->timer = WMAddTimerHandler(BALLOON_DELAY,
  350.                         (WMCallback*)showBalloon, scr);
  351.     }
  352. }
  353.  
  354.  
  355.  
  356. static void
  357. appiconBalloon(WObjDescriptor *object)
  358. {
  359.     WAppIcon *aicon = (WAppIcon*)object->parent;
  360.     WScreen *scr = aicon->icon->core->screen_ptr;
  361.     char *tmp;
  362.  
  363.     if (aicon->command && aicon->wm_class) {
  364.     tmp = wmalloc(strlen(aicon->command)+strlen(aicon->wm_class)+8);
  365.     sprintf(tmp, "%s (%s)", aicon->wm_class, aicon->command);
  366.     scr->balloon->text = tmp;
  367.     } else if (aicon->command) {
  368.     scr->balloon->text = wstrdup(aicon->command);
  369.     } else if (aicon->wm_class) {
  370.     scr->balloon->text = wstrdup(aicon->wm_class);
  371.     } else {
  372.     wBalloonHide(scr);
  373.     return;
  374.     }
  375.     scr->balloon->h = aicon->icon->core->height-2;
  376.  
  377.     scr->balloon->objectWindow = aicon->icon->core->window;
  378.     if ((scr->balloon->prevType == object->parent_type
  379.     || scr->balloon->prevType == WCLASS_MINIWINDOW)
  380.     && scr->balloon->ignoreTimer) {
  381.     XUnmapWindow(dpy, scr->balloon->window);
  382.     showBalloon(scr);
  383.     } else {
  384.     scr->balloon->timer = WMAddTimerHandler(BALLOON_DELAY,
  385.                         (WMCallback*)showBalloon, scr);
  386.     }
  387. }
  388.  
  389.  
  390.  
  391. void
  392. wBalloonInitialize(WScreen *scr)
  393. {
  394.     WBalloon *bal;
  395.     XSetWindowAttributes attribs;
  396.     unsigned long vmask;
  397.     
  398.     bal = wmalloc(sizeof(WBalloon));
  399.     memset(bal, 0, sizeof(WBalloon));
  400.     
  401.     scr->balloon = bal;
  402.  
  403.     vmask = CWSaveUnder|CWOverrideRedirect|CWColormap|CWBackPixel
  404.     |CWBorderPixel;
  405.     attribs.save_under = True;
  406.     attribs.override_redirect = True;
  407.     attribs.colormap = scr->w_colormap;
  408.     attribs.background_pixel = scr->icon_back_texture->normal.pixel;
  409.     attribs.border_pixel = 0; /* do not care */
  410.  
  411.     bal->window = XCreateWindow(dpy, scr->root_win, 1, 1, 10, 10, 1,
  412.                 scr->w_depth, CopyFromParent,
  413.                 scr->w_visual, vmask, &attribs);
  414. #if 0
  415.     /* select EnterNotify to so that the balloon will be unmapped
  416.      * when the pointer is moved over it */
  417.     XSelectInput(dpy, bal->window, EnterWindowMask);
  418. #endif
  419. }
  420.  
  421.  
  422.  
  423. void
  424. wBalloonEnteredObject(WScreen *scr, WObjDescriptor *object)
  425. {
  426.     WBalloon *balloon = scr->balloon;
  427.     
  428.     if (balloon->timer) {
  429.     WMDeleteTimerHandler(balloon->timer);
  430.     balloon->timer = NULL;
  431.     balloon->ignoreTimer = 0;
  432.     }
  433.  
  434.     if (scr->balloon->text)
  435.     free(scr->balloon->text);
  436.     scr->balloon->text = NULL;
  437.  
  438.     if (!object) {
  439.     wBalloonHide(scr);
  440.     balloon->ignoreTimer = 0;
  441.     return;
  442.     }
  443.     switch (object->parent_type) {
  444.      case WCLASS_FRAME:
  445.     if (wPreferences.window_balloon) {
  446.         frameBalloon(object);
  447.     }
  448.     break;
  449.  
  450.      case WCLASS_DOCK_ICON:
  451.     if (object->parent != scr->clip_icon && wPreferences.appicon_balloon)
  452.         appiconBalloon(object);
  453.         else
  454.             wBalloonHide(scr);
  455.     break;
  456.  
  457.      case WCLASS_MINIWINDOW:
  458.     if (wPreferences.miniwin_balloon) {
  459.         miniwindowBalloon(object);
  460.     }
  461.     break;
  462.      case WCLASS_APPICON:
  463.     if (wPreferences.appicon_balloon)
  464.         appiconBalloon(object);
  465.     break;
  466.      default:
  467.     wBalloonHide(scr);
  468.     break;
  469.     }
  470.     scr->balloon->prevType = object->parent_type;
  471. }
  472.  
  473.  
  474.  
  475. void
  476. wBalloonHide(WScreen *scr)
  477. {
  478.     if (scr) {
  479.     if (scr->balloon->mapped) {
  480.         XUnmapWindow(dpy, scr->balloon->window);
  481.         scr->balloon->mapped = 0;
  482.     } else if (scr->balloon->timer) {
  483.         WMDeleteTimerHandler(scr->balloon->timer);
  484.         scr->balloon->timer = NULL;
  485.     }
  486.     scr->balloon->prevType = 0;
  487.     }
  488. }
  489. #endif
  490.